package main;

import grids.FirstFloor;
import grids.SecondFloor;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.TimerTask;

import javax.swing.*;

import spells.*;
import creatures.*;


public final class BattleGridTest2 extends JFrame implements ActionListener, KeyListener{

	/* Initialize main variables used by GridTest, including Grid used, active player, active enemy and test variables
	 * Set position of starting characters
	 */
	static Grid currentGrid;
	static Player you;
	static double timeUntilNextAct = 0;//this stays probably
	static double eTimeUntilNextAct = 0;//this stays probably
	//combat variables (some for testing only)
	//Creature enemy;
	Timer gridTimer;
	Cell currentCell;//contains what cell has last been clicked
	//all becomes Character.health, Character.strength etc

	
	Grid next;//next map to go to
	
	Enemy boss;

	
	int xWin;//x square for winner
	int yWin;//y square for winner
	
	//

	boolean inCombat=true;
	
	//panel for drawing images
	TestingPanel currentPanel;
	static ConsolePanel console;
	public static int ROWS = 12;
	public static int COLUMNS = 16;
	//array labels for icons - uses special ImageLabel class instead of JLabel to store coordinates
	ImageLabel [][] labels = new ImageLabel[ROWS][COLUMNS];
	public static int WIDTH = 824;
	public static int HEIGHT = 620;
	int weaponDamage;
	double attackSpeed;
	JTextArea textArea;
	public BattleGridTest2 (Player p, Grid n){
		inCombat=false;
		boss=null;
		//DALTON - initialize player, enemy health
		you=p;
		next=n;
		weaponDamage = you.weapon1.damage;
		attackSpeed = you.weapon1.attackSpeed;
		
		//note by ben: 8 = rows, 6 = columns
		//Grid grid1 = new Grid(COLUMNS,ROWS,1);
		
		currentGrid = new FirstFloor(you);
		currentGrid.tile = new String("tiles/dirt.jpg");
		
		next=new SecondFloor(you);
		next.tile=new String("tiles/dirt.jpg");
		//place occupants in Grid - is also needed in addition to characters grid method

		//grid1.putOccupant(you.x, you.y, you);
		/*ArrayList<Creature> enemies=new ArrayList<Creature>();
		enemies.add(new Wolf(5,3,"Wolf 1"));
		enemies.get(0).x=5;
		enemies.get(0).y=3;
		
		enemies.add(new Wolf(2,8,"Wolf 2"));
		enemies.get(1).x=2;
		enemies.get(1).y=8;
		
		enemies.add(new Wolf(6,9,"Wolf 3"));
		enemies.get(2).x=6;
		enemies.get(2).y=9;
		grid1.creatures = enemies;
		grid1.creaturesToGrid();*/
		
		Dimension d = new Dimension (WIDTH,HEIGHT+350);
		this.setSize(d);
		/*this.setMaximumSize(d);
        this.setMinimumSize(d);*/
		//this.setLayout(new GridLayout(1,1));
		this.setLayout(new BorderLayout());
		currentPanel = new TestingPanel(WIDTH,HEIGHT);
		currentPanel.currentCell=you.host;
		add(currentPanel, BorderLayout.NORTH);
		currentPanel.you=this.you;
		
		console = new ConsolePanel();
		add(console, BorderLayout.SOUTH);
		currentPanel.requestFocusInWindow();
		this.setVisible(true);
		//this.setResizable(false);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.addKeyListener(this);
	
		
		//timer for repainting of images - also can slow user input down if interval is bad; could use improvement
		
		gridTimer = new Timer(20,new ActionListener() {
			  // This is how you define an anonymous inner class
			  public void actionPerformed(ActionEvent e) {
			    if (next!=null && !you.checkDeath()){
			    	currentPanel.requestFocus();
			    	currentPanel.fillOccImages();
			    	combat(currentGrid.creatures);
			    }
			  }//end method
			});//end ActionListener
		gridTimer.start();
	}//end constructor
	
	
	
	/*
	 * Needs to be fixed to allow movement again
	 */
	
	//Dalton/Richard - method called when creatures exist in grid - manages turns and combat between main character
	//and enemies, takes ArrayList of enemies as parameter
	public void combat(ArrayList <Creature> creatures){
		boolean winFlag=false;
		this.console.pHealth.setText(you.curHealth+"/"+you.maxHealth);
		this.console.pMana.setText(you.curMana+"/"+you.maxMana);
		//Creature enemy = creatures.get(0);
		for(int i=0;i<creatures.size() && !winFlag;i++){
			//all becomes Character.health, Character.strength etc		
			Enemy enemy=(Enemy)creatures.get(i);
			int flag = 0;
			int damage = 0;
			if (flag == 0 && creatures.size()!=0)
				{
					if (timeUntilNextAct <= 0) //USER ACTION
					{
						int x=1+1;
						/*if (!inCombat) {
							timeUntilNextAct = 0;
						}*/
					}//end if
					//other actions can include: spells, MOVING (should take a set time, ex: 0.5)
		
					else if (enemy.eTimeUntilNextAct <= 0)//ENEMY ACTION. must make work for multi enemies later
					{
						if (currentGrid.getDToEnemy(enemy) > 1) {
							enemy.ai(enemy, you);
							//enemy.eTimeUntilNextAct += enemy.movementSpeed;//needs to be moved into enemy
							//enemy.eTimeUntilNextAct += 0.5;//needs to be moved into enemy
						}//end if
						else {
							if (enemy.spells.size() > 0) {
								for (int i1 = 0; i1 < enemy.spells.size(); i1++) {
									if(enemy.spells.get(i1).cManaChange < enemy.curMana) {
										damage = enemy.spells.get(i1).healthChange;
										console.textArea.append("Enemy casts " + enemy.spells.get(i1).getName() + " you for " + damage + " damage.");
										you.curHealth = you.curHealth - damage;
										console.textArea.append("Your Health is now: " + you.curHealth + "/" + you.maxHealth);
									}
								}
							}
							else {
							damage = Player.attackDamage(enemy.strength,enemy.weapon1.damage,enemy.level,you.armor);
							console.textArea.append("Enemy attacks you for " + damage + " damage.");
							you.curHealth = you.curHealth - damage;
							console.textArea.append("Your Health is now: " + you.curHealth + "/" + you.maxHealth);
							enemy.eTimeUntilNextAct = enemy.eTimeUntilNextAct + enemy.weapon1.attackSpeed;
							}
						}//end else
					}//right now only chooses to attack, enemy may use other actions later.
					//other actions can include: spells, MOVING (should take a set time, ex: 0.5)
					//AI: move towards player if player is not adjacent
					else
					{
						//reason for this division by creature size is that the player gets an action check (including minus on time until next) every time a
						//creature acts. This was why only one creature was acting at a time.
						timeUntilNextAct = timeUntilNextAct - (0.1/creatures.size());
						enemy.eTimeUntilNextAct = enemy.eTimeUntilNextAct - 0.1;
						
						for (int n=0; n < you.buffs.size(); n++)
						{
							
							
							if (you.buffs.get(n) instanceof DoT)
							{
								DoT temp = (DoT)(you.buffs.get(n));
								if (temp.getTimeSinceTick() >= temp.getTickTime())
								{
									//DO THE DAMAGE
									you.changeHealth(temp.getDamage());
									temp.displayChange(you.name);
									you.displayHealth();
									//System.out.print(you.name + " changes " + temp.getDamage() + " damage from " + temp.getName());
									temp.setTimeSinceTick(temp.getTimeSinceTick()-temp.getTickTime());
								}
								
								temp.setTimeSinceTick(temp.getTimeSinceTick() + (0.1/creatures.size()));
								
								//EXPERIMENTAL
								temp.setDuration(temp.getDuration() - (0.1/creatures.size()));
								
								if (temp.getDuration() <= 0)
								{
									
									console.textArea.append(you.buffs.get(n).getName() + " duration ends.");
									you.buffs.remove(n);
									
								}
								//removing buff after its gone
							}
							else
							{
								StatusEffect temp = you.buffs.get(n);
								temp.setDuration(temp.getDuration() - (0.1/creatures.size()));
								
								if (temp.getDuration() <= 0)
								{
									console.textArea.append(you.buffs.get(n).getName() + " duration ends.");
									if (you.buffs.get(n) instanceof StatChange)
									{
										((StatChange)(you.buffs.get(n))).removeBuff(you);
									}
									you.buffs.remove(n);
									
								}
							}
						}//checks DoT ticks for player
						
						for (int n=0; n < enemy.buffs.size(); n++)
						{
							if (enemy.buffs.get(n) instanceof DoT)
							{
								DoT temp = (DoT)(enemy.buffs.get(n));
								if (temp.getTimeSinceTick() >= temp.getTickTime())
								{
									//DO THE DAMAGE
									//enemy.curHealth+= temp.getDamage();
									//System.out.println(enemy.name + " changes " + temp.getDamage() + " damage from " + temp.getName());
									enemy.changeHealth(temp.getDamage());
									temp.displayChange(enemy.name);
									temp.setTimeSinceTick(temp.getTimeSinceTick()-temp.getTickTime());
									
									
									//boolean flag2=wolf.checkDeath();
									//if(flag2){
									//	System.out.println(wolf.name+" has died");
									//	you.gainXP(((Enemy)wolf).experience, ((Enemy)wolf).level);
									//	creatures.remove(wolf);
									//	currentCell.occ1=null;
									//}
								}
								
								temp.setTimeSinceTick(temp.getTimeSinceTick() + 0.1);
								
								//EXPERIMENTAL
								temp.setDuration(temp.getDuration() - 0.1);
								
								if (temp.getDuration() <= 0)
								{
									console.textArea.append(enemy.buffs.get(n).getName() + " duration ends.");
									enemy.buffs.remove(n);
									
								}
								//removing buff after its gone
							}
							else
							{
								StatusEffect temp = enemy.buffs.get(n);
								temp.setDuration(temp.getDuration() - (0.1/creatures.size()));
								
								if (temp.getDuration() <= 0)
								{
									console.textArea.append(enemy.buffs.get(n).getName() + " duration ends.");
									if (enemy.buffs.get(n) instanceof StatChange)
									{
										((StatChange)(enemy.buffs.get(n))).removeBuff(enemy);
									}
									enemy.buffs.remove(n);
									
								}
							}
							
							
						}//Make it work for n number of creatures eventually.
						
						
						
					}//end else
		
					if (you.curHealth <= 0 && flag!=1)
					{
						console.textArea.append("You have died!");
						flag = 1;
					}//end if
				
					boolean deathFlag=enemy.checkDeath();
					if(deathFlag){
						console.textArea.append(enemy.name+" has died");
						you.gainXP(enemy.experience, enemy.level);
						creatures.remove(enemy);
						if(enemy==boss)
							boss=null;
						flag=1;
						enemy=null;
					//	wolf=null;
					}//end if
					if(checkWin() && flag!=1){
						if(!winFlag)
							console.textArea.append("You've won");
						winFlag=true;
					}//end if
					currentPanel.fillOccImages();
			}//end if
		}//end for
	}//end method

	//Richard: controls creature commands - how creature will follow human around the grid.  Method called
	//in combat method

	//this checks to see if a user has won
	public boolean checkWin(){
		boolean saved=false;
		int winType = currentGrid.winType;
		if(winType==1){//kill all creatures
			if(currentGrid.creatures.size()==0){
				save();
				currentGrid=next;
				currentPanel=new TestingPanel(WIDTH,HEIGHT); 
				you.curHealth=you.maxHealth;
				you.curMana=you.maxMana;
				return true;
			}//end if
			else
				return false;
		}//end if
		else if(winType==2){//reach a certain square
			if(you.x==xWin && you.y==yWin){
				save();
				return true;
			}//end if
			else
				return false;
		}//end else if
		else if(winType==3){//kill a boss
			if(currentGrid.boss==null){
				save();
				return true;
			}//end if
			else
				return false;
		}//end else if
		return false;
	}//end method

	//save character data
	public boolean save(){
		try{
			BufferedWriter outputStream=new BufferedWriter(new FileWriter("save.txt"));
			String out;
			if(next!=null)
				 out=(currentGrid.floor+1)+"\n"+you;
			else
				 out=currentGrid.floor+"\n"+you;
			outputStream.write(out);
			outputStream.flush();
			return true;
		}//end try
		catch(IOException e){
			return false;
		}
	}//end method
	
	//controls user input - user input only works if it is the user's turn, problems MAY occur due to thread conflicts
	public void keyPressed(KeyEvent e) 
	{/*
		int code = e.getKeyCode();
		System.out.println(KeyEvent.VK_F);
		System.out.println(code);
		synchronized(this){
			if (code == KeyEvent.VK_UP || code == KeyEvent.VK_DOWN || code == KeyEvent.VK_LEFT || code == KeyEvent.VK_RIGHT || code == KeyEvent.VK_A || code==KeyEvent.VK_1 || code==KeyEvent.VK_2 || code==KeyEvent.VK_3 || code==KeyEvent.VK_4 || code==KeyEvent.VK_5 || code==KeyEvent.VK_6 || code==KeyEvent.VK_7 || code==KeyEvent.VK_8 || code==KeyEvent.VK_9 || code==KeyEvent.VK_0){
				if (timeUntilNextAct <= 0){
					if (code == KeyEvent.VK_UP)
					{
						currentGrid.getPC().moveUp();
						timeUntilNextAct += 0.5;
					}//end else if
					else if (code == KeyEvent.VK_DOWN)
					{
						currentGrid.getPC().moveDown();
						timeUntilNextAct += 0.5;
					}//end else if
					else if (code == KeyEvent.VK_LEFT)
					{
						currentGrid.getPC().moveLeft();
						timeUntilNextAct += 0.5;
					}//end else if
					else if (code == KeyEvent.VK_RIGHT)
					{
						currentGrid.getPC().moveRight();
						timeUntilNextAct += 0.5;
					}//end else if
					else if(code==KeyEvent.VK_1){
						//System.out.println("REACHED;");
						Spell temp=you.findSpell("Fireball");
						temp.setTarget((Creature) currentPanel.currentCell.getOccupant());
						String cast = temp.applySpell(currentGrid);
						temp.setTarget(null);
						timeUntilNextAct=timeUntilNextAct+temp.getCastTime();
						System.out.println(cast);
					}//end else if
				
				else if(code==KeyEvent.VK_2){
					Spell temp=you.findSpell("Heal");
					String cast = temp.applySpell(currentGrid);
					System.out.println(cast);
					timeUntilNextAct=timeUntilNextAct+temp.getCastTime();
					this.console.textArea.append("\n"+you.name+"'s health is now "+you.curHealth+"/"+you.maxHealth);
					//System.out.println(you.name+"'s health is now "+you.curHealth+"/"+you.maxHealth);
				}//end else if
				else if(code==KeyEvent.VK_3){
					Spell temp=you.findSpell("Ignite");
					temp.setTarget((Creature) currentPanel.currentCell.getOccupant());
					String cast = temp.applySpell(currentGrid);
					temp.setTarget(null);
					timeUntilNextAct = timeUntilNextAct + temp.getCastTime();
					System.out.println(cast);
				}//end else if
				else if(code==KeyEvent.VK_4){
					Spell temp=you.findSpell("Replenish");
					temp.setTarget((Creature) currentPanel.currentCell.getOccupant());
					String cast = temp.applySpell(currentGrid);
					temp.setTarget(null);
					timeUntilNextAct = timeUntilNextAct + temp.getCastTime();
					System.out.println(cast);
				}//end else if
				else if(code==KeyEvent.VK_5){
					Spell temp=you.findSpell("Pain Spike");
					temp.setTarget((Creature) currentPanel.currentCell.getOccupant());
					String cast = temp.applySpell(currentGrid);
					temp.setTarget(null);
					timeUntilNextAct = timeUntilNextAct + temp.getCastTime();
					System.out.println(cast);
				}//end else if
				else if (code == KeyEvent.VK_A){
					//Enemy temp=(Enemy)currentPanel.currentCell.getOccupant();
					if (!(currentPanel.currentCell.getOccupant() instanceof Enemy)){
						this.console.textArea.append("\nSorry, but selected cell contains not an enemy.");
						//JOptionPane.showMessageDialog(null, "Sorry, but selected cell contains not an enemy.");
						gridTimer.restart();
					}//end if
					else{
						Enemy temp=(Enemy)currentPanel.currentCell.getOccupant();
						if (currentGrid.getDToEnemy(temp) <= 1){
							int damage = Player.attackDamage(you.strength,weaponDamage,you.level,temp.armor);
							System.out.println("You attack enemy for " + damage + " damage.");
							temp.takeDamage(damage);
							System.out.println("Enemy Health is now: " + temp.curHealth + "/" + temp.maxHealth);
							timeUntilNextAct = timeUntilNextAct + attackSpeed;
						}//end if
					}//end else
				}//end else if
		//		currentPanel.fillOccImages();
	
				}//end if
				if(checkWin())
					System.out.println("You've won");
			}//end if
		}//end synchronized*/
	}//end if key is valid
	
	public void keyReleased(KeyEvent e) {
	}//end method

	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}//end method
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

	}//end method

	public static class ConsolePanel extends JPanel{
		static JLabel pHealth;
		static JLabel pHealthLabel;
		static JLabel pMana;
		static JLabel pManaLabel;
		
		static JLabel eName;
		static JLabel eNameLabel;
		static JLabel eHealth;
		static JLabel eHealthLabel;
		static JLabel eMana;
		static JLabel eManaLabel;
		
		static JTextArea textArea;
		public ConsolePanel(){
			this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
			JPanel textPanel=new JPanel();
			textPanel.setPreferredSize(new Dimension(824,200));
			JPanel infoPanel=new JPanel();
			infoPanel.setLayout(new GridLayout(1,3));
			infoPanel.setPreferredSize(new Dimension(824,100));
			
			JPanel playerPanel=new JPanel();
			playerPanel.setLayout(new GridLayout(3,1));
			JPanel enemyPanel=new JPanel();
			enemyPanel.setLayout(new GridLayout(3,1));
			
			pHealth=new JLabel();
			pHealth.setPreferredSize(new Dimension(200,20));
			//pHealth.setEditable(false);
			pHealthLabel=new JLabel(you.name+" Health:");
			pMana=new JLabel();
			pMana.setPreferredSize(new Dimension(200,20));
			//pMana.setEditable(false);
			pManaLabel=new JLabel(you.name+" Mana:");
			
			eNameLabel=new JLabel("Enemy:");
			eName=new JLabel();
			eName.setPreferredSize(new Dimension(100,20));
			eHealth=new JLabel();
			eHealth.setPreferredSize(new Dimension(100,20));
			//pHealth.setEditable(false);
			eHealthLabel=new JLabel("Health:");
			eMana=new JLabel();
			eMana.setPreferredSize(new Dimension(100,20));
			//pMana.setEditable(false);
			eManaLabel=new JLabel("Mana:");
			
			textArea = new JTextArea("THIS IS AN INITIAL TEST"); 
			textArea.setPreferredSize(new Dimension(200,100));
			JScrollPane scrollPane = new JScrollPane(textArea);
			scrollPane.setVisible(true);
			scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
			scrollPane.setPreferredSize(new Dimension(824,100));
			//scrollPane.getViewport().add(textArea);
			textArea.setEditable(true);
			playerPanel.add(pHealthLabel);
			playerPanel.add(pHealth);
			playerPanel.add(pManaLabel);
			playerPanel.add(pMana);
			
			enemyPanel.add(eNameLabel);
			enemyPanel.add(eName);
			enemyPanel.add(eHealthLabel);
			enemyPanel.add(eHealth);
			enemyPanel.add(eManaLabel);
			enemyPanel.add(eMana);
			
			infoPanel.add(playerPanel);
			infoPanel.add(enemyPanel);
			
			//this.add(textArea);
			textPanel.add(scrollPane);
			add(textPanel);
			add(infoPanel);
			Dimension d = new Dimension (824,400);
			this.setMaximumSize(d);
			this.setMinimumSize(d);
			this.setSize(d);
		}//end constructor
	}//end console panel
	/* 
	 * Special labels with icons
	 */
	
	public class ImageLabel extends JLabel{
		int x;
		int y;
		public ImageLabel(String s, ImageIcon image, int x, int y){
			Dimension label = new Dimension(50,50);
			setMinimumSize(label);
			setMaximumSize(label);
			setSize(label);
			this.x = x;
			this.y = y;
			//setText(s);
			this.setIcon(image);
			//this.setText(labelT);
		}//end constructor
		public void setCoords(int x, int y){
			this.x = x; 
			this.y = y;
		}//end method
	}//end class

}//end class
